using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;

namespace Infinity.Common.Logger
{
	public class HtmlLogger : LoggerBase
	{
		public HtmlLogger(string fileName)
		{
			if (string.IsNullOrWhiteSpace(fileName))
				throw new ArgumentNullException("fileName");

			DateTimeFormat = @"dd/MM/yyyy hh:mm:ss";
			Title = "Log file";

			CSS = DEFAULT_CSS;

			FileName = fileName;

			if (!File.Exists(FileName))
				InitHtmlLogFile(FileName);
		}

		/// <summary>
		/// Create a new blank html log file.
		/// </summary>
		protected void InitHtmlLogFile(string fileName)
		{
			var xDocument = new XDocument(
				new XElement("html",
				             new XElement("head",
				                          new XElement("title", Title),
				                          new XElement("style", CSS)),
				             new XElement("body",
				                          new XElement("h1", Title),
				                          new XElement("table",
				                                       new XElement("tr",
				                                                    new XElement("th", new XAttribute("class", "time"), "Time"),
				                                                    new XElement("th", new XAttribute("class", "type"), "Log type"),
				                                                    new XElement("th", new XAttribute("class", "message"), "Message"))
					                          ))));

			xDocument.Save(fileName);
		}

		public string FileName { get; set; }

		/// <summary>
		/// Default css style for generated HTML log file
		/// </summary>
		public readonly string DEFAULT_CSS =
			@"body{ font-family:Verdana,Arial; font-size:14px}table{ font-family:inherit; font-size:inherit; border-spacing:0px; table-layout:auto; width:100%; margin-left:auto; margin-right:auto}table th{ background:gray; color:white; text-transform:uppercase; font-size:11px}table .time{ width:15%}table .type{ width:5%}table td{ padding:5px; text-align:center}.info{ background:green}.error{ background:red}.warning{ background:yellow} .alert{ background:darkred}";

		private string _title;

		/// <summary>
		/// CSS style for HTML webpage
		/// </summary>
		public string CSS { get; set; }

		/// <summary>
		/// Title of webpage
		/// </summary>
		public string Title
		{
			get { return _title; }
			set
			{
				_title = value;

				if (File.Exists(FileName))
				{
					XDocument xDocument = XDocument.Load(FileName);
					var title = xDocument.XPathSelectElement(@"//title");

					if (title != null)
						title.SetValue(Title);

					xDocument.Save(FileName);
				}
			}
		}

		/// <summary>
		/// Format of date time
		/// </summary>
		public string DateTimeFormat { get; set; }

		protected XElement CreateNode(Log log)
		{
			if (log == null)
				throw new ArgumentNullException("log");

			var element = new XElement("tr",
			                           new XAttribute("class", log.LogType),
			                           new XElement("td", log.Time.ToString(DateTimeFormat)),
			                           new XElement("td", log.LogType),
			                           new XElement("td", log.Message));

			return element;
		}

		protected void AddNewNode(Log log)
		{
			XDocument xDocument = XDocument.Load(FileName);
			var xmlRows = xDocument.XPathSelectElements(@"//tr");
			if (xmlRows.Any())
			{
				xmlRows.Last().AddAfterSelf(
					CreateNode(log)
					);
			}

			xDocument.Save(FileName);
		}

		public override void Flush()
		{
			InitHtmlLogFile(FileName);
		}

		public override void Alert(string text)
		{
			AddNewNode(new Log(text, LogType.Alert));
		}

		public override void Info(string text)
		{
			AddNewNode(new Log(text, LogType.Info));
		}

		public override void Warning(string text)
		{
			AddNewNode(new Log(text, LogType.Warning));
		}

		public override void Error(string text)
		{
			AddNewNode(new Log(text, LogType.Error));
		}

		public override void Write(string text = "")
		{
			AddNewNode(new Log(text));
		}
	}
}